package com.drg.center.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.drg.center.dao.SysRoleResourcesDAO;
import com.drg.center.entity.enums.ResTypeEnum;
import com.drg.center.entity.param.ResourcesAddDTO;
import com.drg.center.entity.param.ResourcesEditDTO;
import com.drg.center.entity.result.SysResVO;
import com.drg.center.entity.result.SysResourcesVO;
import com.guaike.core.entity.constant.ViewConstant;
import com.guaike.core.entity.exception.ApiException;
import com.guaike.core.entity.exception.ParamException;
import com.guaike.core.entity.result.Result;
import com.guaike.core.utils.CompareUtil;
import com.guaike.core.utils.ListUtil;
import com.drg.center.dao.SysResourcesDAO;
import com.drg.center.entity.SysResourcesPO;
import com.drg.center.entity.SysRoleResourcesPO;
import com.drg.center.service.SysResourcesService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: zhangxilin
 * @Date: 2023/10/30
 */
@Slf4j
@Service
public class SysResourcesServiceImpl implements SysResourcesService {

    @Autowired
    private SysResourcesDAO sysResourcesDAO;
    @Autowired
    private SysRoleResourcesDAO sysRoleResourcesDAO;

    @Autowired
    private DataSourceTransactionManager transactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;

    @Override
    public List<SysResVO> buildTree(List<SysResourcesPO> resourcesPOList) {
        List<SysResVO> list =new ArrayList<>();
        for(SysResourcesPO po: resourcesPOList){
            // 先找到所有的一级节点
            if(po.getPid() !=null){
                continue;
            }
            SysResVO vo = new SysResVO();
            BeanUtils.copyProperties(po,vo);
            vo.setChildren(getChild(resourcesPOList,po.getId()));
            list.add(vo);
        }
        return list;
    }

    private List<SysResVO> getChild(List<SysResourcesPO> resourcesPOList,Long pid){
        List<SysResVO> childList =new ArrayList<>();
        for(SysResourcesPO po: resourcesPOList){
            if(po.getPid() !=null &&  po.getPid().compareTo(pid) ==0){
                SysResVO vo = new SysResVO();
                BeanUtils.copyProperties(po,vo);
                childList.add(vo);
            }
        }
        // 退出递归调用条件
        if(CollectionUtils.isEmpty(childList)){
            return null;
        }
        for(SysResVO vo: childList){
            vo.setChildren(getChild(resourcesPOList,vo.getId()));
        }
        return childList;
    }


    @Override
    public Result<List<Tree<Long>>> findTree(String sysCode, Boolean onlyMenu) {
        List<SysResourcesVO> resList = findList(sysCode, onlyMenu? Boolean.TRUE: Boolean.FALSE);

        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setIdKey("id");
        treeNodeConfig.setParentIdKey("pid");
        treeNodeConfig.setNameKey("name");
        treeNodeConfig.setWeightKey("sortIndex");

        List<Tree<Long>> trees = TreeUtil.build(resList, null,treeNodeConfig,
                (po, tree) -> {
                    tree.setId(po.getId());
                    tree.setName(po.getName());
                    tree.setParentId(po.getPid());
                    tree.setWeight(po.getSortIndex());
                    tree.putExtra("extra", po);
                });
        return Result.success().data(trees).build();
    }

    @Override
    public Result<SysResourcesVO> detail(Long id) {
        SysResourcesPO po = sysResourcesDAO.findById(id);
        if(po == null){
            return Result.failure().message("记录不存在").build();
        }
        SysResourcesVO vo = new SysResourcesVO();
        BeanUtil.copyProperties(po, vo);
        return Result.success().data(vo).build();
    }

    @Override
    public Result<Boolean> add(ResourcesAddDTO param) {
        String traceIds = null;
        SysResourcesPO parentPO = null;
        if(param.getPid() != null){
            parentPO = sysResourcesDAO.findById(param.getPid());
            if(parentPO == null){
                return Result.failure().message("父级资源不存在").build();
            }
            traceIds = StringUtils.isBlank(parentPO.getTraceIds())? parentPO.getId()+"": parentPO.getTraceIds()+ ViewConstant.COMMA_DISP+  parentPO.getId();
        }

        checkRes(parentPO, param.getResType());

        SysResourcesPO record = new SysResourcesPO();
        BeanUtil.copyProperties(param, record);
        record.setTraceIds(traceIds);
        setRecord(record);
        sysResourcesDAO.save(record);
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    public Result<Boolean> edit(ResourcesEditDTO param) {
        SysResourcesPO record = sysResourcesDAO.findById(param.getId());
        if(record == null){
            return Result.failure().message("记录不存在").build();
        }
        BeanUtil.copyProperties(param, record);
        setRecord(record);

        sysResourcesDAO.updateById(record);
        return Result.success().data(Boolean.TRUE).build();
    }

    private void setRecord(SysResourcesPO record){
        if(!CompareUtil.isEqual(record.getResType(), ResTypeEnum.menu.getCode())){
            record.setRouter("");
        }
    }
    private void checkRes(SysResourcesPO parentPO, Integer resType){
        if(CompareUtil.isEqual(resType, ResTypeEnum.button.getCode()) ){
            if(parentPO == null){
                throw new ParamException("添加的按钮必须有所属父节点");
            }
            if(!CompareUtil.isEqual(parentPO.getResType(),  ResTypeEnum.menu.getCode()) ){
                throw new ParamException("添加的按钮父节点必须是菜单");
            }
        }
    }

    @Override
    public Result<Boolean> delete(Long id) {
        SysResourcesPO record = sysResourcesDAO.findById(id);
        if(record == null){
            return Result.failure().message("记录不存在").build();
        }
        String traceIds = StringUtils.isBlank(record.getTraceIds())? record.getId()+"": record.getTraceIds()+ ViewConstant.COMMA_DISP+  record.getId();

        List<Long> idList = Lists.newArrayList();
        List<SysResourcesPO> poList = sysResourcesDAO.findSubList(traceIds);
        if(!CollectionUtils.isEmpty(poList)){
            idList = poList.stream().map(SysResourcesPO::getId).collect(Collectors.toList());
        }
        idList.add(id);

        TransactionStatus transactionStatus= transactionManager.getTransaction(transactionDefinition);
        try{
            sysResourcesDAO.removeByIds(idList);
            sysRoleResourcesDAO.delIn(SysRoleResourcesPO::getResId, idList);
            transactionManager.commit(transactionStatus);
        }catch (Exception e){
            log.error("执行事务异常，需要回滚 e:{}",e);
            transactionManager.rollback(transactionStatus);
            throw new ApiException(e.getMessage());
        }
        return Result.success().data(Boolean.TRUE).build();
    }

    private List<SysResourcesVO> findList(String sysCode, Boolean isExcludeBtn){
        List<SysResourcesPO> poList = sysResourcesDAO.findList(sysCode, isExcludeBtn);
        if(CollectionUtils.isEmpty(poList)){
            return Lists.newArrayList();
        }
        return ListUtil.copyList(poList, SysResourcesVO.class);
    }
}
